package com.yunyike.app.data.service.impl;



import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yunyike.app.constants.CartConstants;
import com.yunyike.app.constants.CommonConstant;
import com.yunyike.app.constants.EnumExchangeRate;
import com.yunyike.app.data.dto.CartDTO;
import com.yunyike.app.data.dto.CartSkuDTO;
import com.yunyike.app.data.model.Merchandise;
import com.yunyike.app.data.model.Shop;
import com.yunyike.app.data.model.ShopPromotion;
import com.yunyike.app.data.model.User;
import com.yunyike.app.data.service.ICartService;
import com.yunyike.app.data.service.IMerchandiseService;
import com.yunyike.app.data.service.IShopPromotionService;
import com.yunyike.app.data.service.IShopService;
import com.yunyike.app.redis.JedisManager;
import com.yunyike.app.util.ExchangeRateUtils;


/**
 * @author zhengqiang.shi
 * 2015年11月22日 上午1:31:02
 */
@Service("cartServiceImpl")
public class CartServiceImpl implements ICartService {

	private Logger log = LoggerFactory.getLogger(CartServiceImpl.class);
	
	@Autowired
	private IMerchandiseService merchandiseService;
	
	@Autowired
	private IShopService shopService;
	
	@Autowired
	private IShopPromotionService shopPromotionService;
	
/*	@Autowired
	private IShopperService shopperService;
	
	@Autowired
	private IRecepientService recepientService;*/
	
	/**
	 * 添加购物车
	 * 修改购物车数量
	 */
	public int addCart(User user, String shopId, String merchandiseBarCode, int qty) {
		
		// 店铺信息
		log.info("----->> find shop by id...");
		Shop shop = shopService.findShopById(shopId);
		
		if(shop == null){
			log.error("no shop for shopId:"+shopId);
			return CommonConstant.NUMBER_0;
		}
		
		// redis key
		log.info("----->> generator cart key...");
		String cartKey = CartConstants.cartKey(user,shop.getShopNumber());
		log.info("cart key:"+cartKey);
		
		// 商品信息
		log.info("find merchandise,barcode:"+merchandiseBarCode);
		Merchandise merchandise = merchandiseService.findMerchandiseByBarCode(merchandiseBarCode);
		if(merchandise == null){
			log.error("no merchandise for merchandiseBarCode:"+merchandiseBarCode);
			return CommonConstant.NUMBER_0;
		}
		
		// 获取当前购物车信息
		log.info("get cart data from redis...");
		CartDTO cartDTO = (CartDTO)JedisManager.getObject(cartKey,CartDTO.class);
		if(cartDTO == null){
			cartDTO = new CartDTO();
		}
		
		// 当前购物车是否存在该商品
		log.info("need add merchandise is exist?");
		CartSkuDTO cartSkuDTO = findCartSkuDTOByMerchandiseBarCode(cartDTO, merchandiseBarCode);
		
		// 添加
		if(cartSkuDTO == null){
			log.info("not exist , add...");
			cartSkuDTO = new CartSkuDTO();
			cartSkuDTO.setMerchandise(merchandise);
			cartSkuDTO.setQty(qty);
			cartDTO.getCartSkuDTOList().add(cartSkuDTO);
		} else{ // 更新
			log.info("exist , update...");
			cartSkuDTO.setQty(cartSkuDTO.getQty()+qty);
		}
		
		// 计算价格
		setPrice(cartDTO);
		
		// 检查重量
		log.info("check weight");
		if(!checkWeight(cartDTO)){
			log.info("add failed.because out of weight.");
			return CommonConstant.NUMBER_2;
		}

		// 检查数量
		log.info("check number");
		if(!checkNumber(cartDTO)){
			log.info("add failed.because out of number.");
			return CommonConstant.NUMBER_3;
		}
		
		// 检查金额
		/*log.info("check price");
		if(!checkPrice(cartDTO)){
			log.info("add failed.because out of price.");
			return CommonConstant.NUMBER_4;
		}*/
		
		// 放入缓存
		log.info("end to add cart.set to redis.");
		JedisManager.setObject(cartKey, CartConstants.CART_OUT_TIME, cartDTO);
		
		return CommonConstant.NUMBER_1;
	}

	/**
	 * 删除购物车
	 */
	public int removeCart(User user, String shopId, String merchandiseBarcode) {
		
		// 店铺信息
		log.info("----->> find shop by id...");
		Shop shop = shopService.findShopById(shopId);
		
		if(shop == null){
			log.error("no shop for shopId:"+shopId);
			return 0;
		}
		
		// redis key
		log.info("----->> generator cart key...");
		String cartKey = CartConstants.cartKey(user,shop.getShopNumber());
		log.info("cart key:"+cartKey);
		
		// 获取当前购物车信息
		log.info("----->> start to get current cart...");
		CartDTO cartDTO = (CartDTO)JedisManager.getObject(cartKey,CartDTO.class);
		if(cartDTO == null){
			log.info("----->> current cart is null.");
			cartDTO = new CartDTO();
		}
		
		// 当前购物车是否存在
		log.info("----->> start to get cartSkuDTO from current cart...");
		CartSkuDTO cartSkuDTO = findCartSkuDTOByMerchandiseBarCode(cartDTO, merchandiseBarcode);
		if(cartSkuDTO == null || cartDTO.getCartSkuDTOList().remove(cartSkuDTO)){
			JedisManager.setObject(cartKey, CartConstants.CART_OUT_TIME, cartDTO);
			log.info("----->> remove cartSkuDTO from current cart success.");
			return CommonConstant.NUMBER_1;
		}
		
		return CommonConstant.NUMBER_0;
	}
	
	/**
	 * 获取购物车信息
	 */
	public CartDTO getCart(User user,String shopId) {
		
		// 店铺信息
		log.info("----->> find shop by id...");
		Shop shop = shopService.findShopById(shopId);
		
		if(shop == null){
			log.error("no shop for shopId:"+shopId);
			return null;
		}
		
		// redis key
		log.info("----->> generator cart key...");
		String cartKey = CartConstants.cartKey(user,shop.getShopNumber());
		log.info("cart key:"+cartKey);
		
		// 获取购物车信息
		log.info("----->> get cart info by user.userId"+user.getUserId()+"\tshopNumber:"+shop.getShopNumber());
		CartDTO cartDTO = (CartDTO)JedisManager.getObject(cartKey,CartDTO.class);
		
		if(cartDTO == null){
			log.info("current user's cart is null.");
			
			cartDTO = new CartDTO();
			// 店铺信息
			log.info("----->> find shop info...");
			cartDTO.setShop(shop);
			
			// 店铺促销信息
			log.info("----->> find promotion info...");
			setPromotion(cartDTO);
			return cartDTO;
		}
		
		// 店铺信息
		log.info("----->> find shop info...");
		cartDTO.setShop(shop);
		
		// 商品信息
		log.info("----->> find merchandise info...");
		setMerchandise(cartDTO);
		
		// 店铺促销信息
		log.info("----->> find promotion info...");
		setPromotion(cartDTO);
		
		// 计算各种价格
		log.info("----->> find price...");
		setPrice(cartDTO);
		
		log.info("----->> end to get cart.");
		return cartDTO;
	}

	private void setMerchandise(CartDTO cartDTO){
		List<CartSkuDTO> cartSkuDTOList = cartDTO.getCartSkuDTOList();
		if(cartSkuDTOList == null || cartSkuDTOList.isEmpty()){
			return;
		}
		
		List<Merchandise> merchandiseList = new ArrayList<Merchandise>();
		for (CartSkuDTO cartSkuDTO : cartSkuDTOList) {
			merchandiseList.add(cartSkuDTO.getMerchandise());
		}
		
		merchandiseList = merchandiseService.findMerchandiseByIds(merchandiseList);
		
		for (CartSkuDTO cartSkuDTO : cartSkuDTOList) {
			String merchandiseId = cartSkuDTO.getMerchandise().getMerchandiseId();
			
			for(Merchandise merchandise : merchandiseList){
				String newMerchandiseId = merchandise.getMerchandiseId();
				
				if(newMerchandiseId.equals(merchandiseId)){
					cartSkuDTO.setMerchandise(merchandise);
				}
			}
		}
	}
	
	private void setPromotion(CartDTO cartDTO) {
		
		String shopId = cartDTO.getShop().getShopId();
		
		List<ShopPromotion> shopPromotionList = shopPromotionService.findPromotionByShopId(shopId);
		
		cartDTO.setShopPromotionList(shopPromotionList);
		
	}
	
	private void setPrice(CartDTO cartDTO){
		// 支付金额
		BigDecimal payAmount = new BigDecimal(0);
		
		// 商品总金额
		BigDecimal itemAmount = new BigDecimal(0);
		
		// 商品总节省金额
		BigDecimal saveAmount = new BigDecimal(0);
		
		// 商品总重量
		BigDecimal totalWeight = new BigDecimal(0);
		
		// 商品总数量
		int totalNumber = 0;
		
		List<CartSkuDTO> cartSkuDTOList = cartDTO.getCartSkuDTOList();
		for (CartSkuDTO cartSkuDTO : cartSkuDTOList) {
			Merchandise merchandise = cartSkuDTO.getMerchandise();
			
			// 单商品小计
			double merchandisePrice = merchandise.getMerchandisePrice() * cartSkuDTO.getQty();
			
			// 国内价
			Double merchandiseDomesticPrice = merchandise.getMerchandiseDomesticPrice() * cartSkuDTO.getQty();
			
			// 换算人民币后的商品价格
			double exchangeRate = ExchangeRateUtils.exchangeRate(EnumExchangeRate.CNY, merchandisePrice);
			
			// 小计
			cartSkuDTO.setSubTotal(new BigDecimal(merchandisePrice));
			
			// 商品总节省金额
			saveAmount = saveAmount.add(new BigDecimal(merchandiseDomesticPrice - exchangeRate));
			
			// 商品总重量
			totalWeight = totalWeight.add(new BigDecimal(merchandise.getMerchandiseWeight() * cartSkuDTO.getQty()));
			
			// 商品总数量
			totalNumber += cartSkuDTO.getQty();
			
			// 商品总金额
			itemAmount = itemAmount.add(new BigDecimal(merchandisePrice));
		}
		
		// 计算活动
		/*List<ShopPromotion> shopPromotionList = cartDTO.getShopPromotionList();
		
		if(shopPromotionList != null && !shopPromotionList.isEmpty()){
			
			// 排序
			Collections.sort(shopPromotionList, new Comparator<ShopPromotion>() {

				public int compare(ShopPromotion o1, ShopPromotion o2) {
					
					return o1.getOrderPrice().compareTo(o2.getOrderPrice());
				}
			});
			
			// 匹配活动
			for (ShopPromotion shopPromotion : shopPromotionList) {
				// 满足金额
				Double orderPrice = shopPromotion.getOrderPrice();
				
				if(itemAmount.compareTo(new BigDecimal(orderPrice)) >= 0){
					itemAmount = itemAmount.multiply(new BigDecimal(shopPromotion.getDiscount()));
					break;
				}
			}
		}*/
		
		// 总金额 = 总金额 * 折扣
		payAmount = itemAmount.multiply(new BigDecimal(CommonConstant.DISCOUNT));
		
		// 总运费
//		BigDecimal freight = new BigDecimal(Math.ceil(totalWeight.doubleValue()/1000)*CommonConstant.SINGLE_BOX_FREIGHT).setScale(2, BigDecimal.ROUND_HALF_UP);
		BigDecimal freight =getFreight(totalWeight, payAmount);
				
		// 总金额 = 商品金额 + 运费
		payAmount = payAmount.add(freight);
		
		cartDTO.setItemAmount(itemAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
		cartDTO.setPayAmount(payAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
		cartDTO.setTotalWeight(totalWeight.setScale(2, BigDecimal.ROUND_HALF_UP));
		cartDTO.setTotalNumber(totalNumber);
		cartDTO.setSaveAmount(saveAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
		cartDTO.setTotalFreight(freight);
		
	}
	
	private BigDecimal getFreight(BigDecimal totalWeight,BigDecimal itemAmount){
		
		if(itemAmount.compareTo(CommonConstant.FREE_SHIPMENT_AMOUNT)>=0
				&&totalWeight.compareTo(new BigDecimal(CommonConstant.FREE_SHIPMENT_WEIGHT))<=0){
			return new BigDecimal(0);
		}
		return CommonConstant.SINGLE_BOX_FREIGHT;
	}
	
	private CartSkuDTO findCartSkuDTOByMerchandiseBarCode(CartDTO cartDTO,String merchandiseBarcode){
		List<CartSkuDTO> cartSkuDTOList = cartDTO.getCartSkuDTOList();
		if(cartSkuDTOList == null || cartSkuDTOList.isEmpty()){
			return null;
		}
		
		for (CartSkuDTO cartSkuDTO : cartSkuDTOList) {
			
			Merchandise merchandise = cartSkuDTO.getMerchandise();
			
			if(merchandise == null){
				continue;
			}
			
			String barCode = merchandise.getMerchandiseBarcode();
			if(barCode.equals(merchandiseBarcode)){
				return cartSkuDTO;
			}
		}
		
		return null;
	}
	
	public int updateCart(User user, String shopId,String merchandiseBarcode, int qty) {
		
		// 店铺信息
		log.info("----->> find shop by id...");
		Shop shop = shopService.findShopById(shopId);
		
		if(shop == null){
			log.error("no shop for shopId:"+shopId);
			return 0;
		}
		
		// redis key
		log.info("----->> generator cart key...");
		String cartKey = CartConstants.cartKey(user,shop.getShopNumber());
		log.info("cart key:"+cartKey);
		
		// 获取当前购物车信息
		log.info("get cart data from redis...");
		CartDTO cartDTO = (CartDTO)JedisManager.getObject(cartKey,CartDTO.class);
		if(cartDTO == null){
			cartDTO = new CartDTO();
		}
		
		// 当前购物车是否存在该商品
		log.info("need update merchandise is exist?");
		CartSkuDTO cartSkuDTO = findCartSkuDTOByMerchandiseBarCode(cartDTO, merchandiseBarcode);
		
		// 不存在无法更新
		if(cartSkuDTO == null){
			log.error("no merchandise from redis");
			return 0;
		}
		// 更新
		log.info("exist , update...");
		cartSkuDTO.setQty(qty);
		
		// 设置价格
		setPrice(cartDTO);
		
		// 检查重量
		log.info("check weight");
		if(!checkWeight(cartDTO)){
			log.info("add failed.because out of weight.");
			return CommonConstant.NUMBER_2;
		}

		// 检查数量
		log.info("check number");
		if(!checkNumber(cartDTO)){
			log.info("add failed.because out of number.");
			return CommonConstant.NUMBER_3;
		}
		
		// 检查金额
		/*log.info("check price");
		if(!checkPrice(cartDTO)){
			log.info("add failed.because out of price.");
			return CommonConstant.NUMBER_4;
		}*/
		
		// 放入缓存
		log.info("end to add cart.set to redis.");
		JedisManager.setObject(cartKey, CartConstants.CART_OUT_TIME, cartDTO);
		
		return CommonConstant.NUMBER_1;
		
	}
	
	/**
	 * 检查每箱的最大重量 每箱2公斤（1.8）
	 * @param cartDTO
	 * @return
	 */
	private boolean checkWeight(CartDTO cartDTO){
		
		BigDecimal totalWeight = cartDTO.getTotalWeight();
		
		log.info("check weight,current weight:"+totalWeight);
		if(CartConstants.MAX_WEIGHT.compareTo(totalWeight) < 1){
			return false;
		}
		
		return true;
	}
	
	/**
	 * 检查每箱的最大金额 每箱120欧元
	 * @param cartDTO
	 * @return
	 */
	/*private boolean checkPrice(CartDTO cartDTO){
		// 需要减去运费
		BigDecimal totalAmount = cartDTO.getPayAmount().subtract(cartDTO.getTotalFreight());
		
		log.info("check price,current price:"+totalAmount);
		if(CartConstants.SINGLE_MAX_PRICE.compareTo(totalAmount) < 1){
			return false;
		}
		
		return true;
	}*/
	
	/**
	 * 检查每箱的商品数量，最大10
	 * @param cartDTO
	 * @return
	 */
	private boolean checkNumber(CartDTO cartDTO){
		
		int totalNumber = cartDTO.getTotalNumber();
		
		log.info("check number,current number:"+totalNumber);
		if(CartConstants.MAX_NUMBER < totalNumber){
			return false;
		}
		
		return true;
	}

	/*public SettlementDTO settlement(User user, String shopId, String sessionId) {
		
		// settlement redis key
		log.info("----->> generator settlement key...");
		String settlementKey = CartConstants.settlementKey(sessionId);
		log.info("settlement key:"+settlementKey);
		
		// 获取当前结算信息
		log.info("get settlement data from redis...");
		SettlementDTO settlementDTO = (SettlementDTO)JedisManager.getObject(settlementKey,SettlementDTO.class);
		
		if(settlementDTO == null){
			log.info("first settlement...");
			settlementDTO = new SettlementDTO();
		}
		
		// set current url of settlement
		String settlementUrlKey = CartConstants.settlementUrlKey(sessionId);
		JedisManager.setString(settlementUrlKey, shopId, CartConstants.SETTLEMENT_OUT_TIME);
		
		// get shopperId
		String shopperId = getCurrentShopper(user);
		
		// 店铺信息
		log.info("----->> find shop by id...");
		Shop shop = shopService.findShopById(shopId);
		
		if(shop == null){
			log.error("no shop for shopId:"+shopId);
			throw new DataNotFoundException();
		}
		
		// 售货员信息
		Shopper shopper = null;
		if(!CommonConstant.SHOPPER_ID.equals(shopperId)){
			log.info("----->> find shopper by id...");
			shopper = shopperService.findShopperById(shopperId);
			if(shopper == null){
				log.error("no shopper for shopperId:"+shopperId);
				throw new DataNotFoundException();
			}
		}else{
			shopper = new Shopper();
			shopper.setShopperId(shopperId);
		}
		
		if(!setCartDTO(user, shop, settlementDTO)){
			return null;
		}
		
		setShopper(shopper, settlementDTO);
		
		setPayment(settlementDTO);
		
		setRecepient(user, settlementDTO);
		
		setCoupon(user, settlementDTO);
		
		JedisManager.setObject(settlementKey, CartConstants.SETTLEMENT_OUT_TIME, settlementDTO);
		
		return settlementDTO;
		
	}

	private String getCurrentShopper(User user) {
		log.info("getCurrentShopper...userId:"+user.getUserId());
		Shopper shopper = (Shopper)JedisManager.getObject(user.getUserId()+CommonConstant.SHOPPER_CONNECT_USER,Shopper.class);
		
		String shopperId = "";
		if(shopper == null){
			shopperId = CommonConstant.SHOPPER_ID;
		}else{
			shopperId = shopper.getShopperId();
		}
		
		log.info("getCurrentShopper...shopperId:"+shopperId);
		return shopperId;
	}
	
	public SettlementDTO getCurrentSettlementInfo(String sessionId){
		// settlement redis key
		log.info("----->> generator settlement key...");
		String settlementKey = CartConstants.settlementKey(sessionId);
		log.info("settlement key:"+settlementKey);
		
		// 获取当前结算信息
		log.info("get settlement data from redis...");
		SettlementDTO settlementDTO = (SettlementDTO)JedisManager.getObject(settlementKey,SettlementDTO.class);
		
		return settlementDTO;
	}
	
	private void setRecepient(User user,SettlementDTO settlementDTO){
		Recepient recepient = settlementDTO.getRecepient();
		if(recepient == null){
			List<Recepient> recepientList = recepientService.findRecepientByUser(user.getUserId());
			if(recepientList == null || recepientList.isEmpty()){
				return;
			}
			recepient = recepientList.get(0);
			settlementDTO.setRecepient(recepient);
		}
	}
	
	private void setPayment(SettlementDTO settlementDTO){
		Payment payment = settlementDTO.getPayment();
		if(payment == null){
			payment = new Payment();
			payment.setPaymentType(PaymentConstants.PAY_TYPE_2);
			settlementDTO.setPayment(payment);
		}
	}
	
	private void setShopper(Shopper shopper, SettlementDTO settlementDTO){
		settlementDTO.setShopper(shopper);
	}
	
	private boolean setCartDTO(User user,Shop shop, SettlementDTO settlementDTO){
		
		CartDTO cartDTO = getCart(user, shop.getShopId());
		
		if(cartDTO == null || cartDTO.getCartSkuDTOList() == null || cartDTO.getCartSkuDTOList().isEmpty()){
			log.info("need settlement data is null");
			return false;
		}
		
		settlementDTO.setCartDTO(cartDTO);
		
		return true;
	}

	private void setCoupon(User user, SettlementDTO settlementDTO) {
		CartDTO cartDTO = settlementDTO.getCartDTO();
		
		// 支付金额
		BigDecimal payAmount = cartDTO.getPayAmount();
		
		List<Coupon> couponList = settlementDTO.getCouponList();
		if(couponList != null && !couponList.isEmpty()){
			for (Coupon coupon : couponList) {
				// 检查优惠券
				checkCoupon(user, payAmount, coupon);
				
				// 优惠金额
				Double couponAmount = coupon.getCouponAmount();
				
				payAmount = payAmount.subtract(new BigDecimal(couponAmount));
				// 优惠到0元为止
				if(payAmount.compareTo(new BigDecimal(0)) < 0){
					payAmount = new BigDecimal(0);
					break;
				}
			}
			cartDTO.setPayAmount(payAmount);
		}
	}

	private void checkCoupon(User user, BigDecimal payAmount, Coupon coupon) {
		// 所属用户
		String userId = coupon.getUserId();
		if(!user.getUserId().equals(userId)){
			log.error("coupon not current user , throw exception.");
			throw new BadRequestException();
		}
		
		// 满足金额
		Double couponUsePrice = coupon.getCouponUsePrice();
		if(payAmount.compareTo(new BigDecimal(couponUsePrice)) < 0){
			log.error("couponUsePrice < totalAmount , throw exception.");
			throw new BadRequestException();
		}
		
		// 优惠券状态
		Integer couponStatus = coupon.getCouponStatus();
		if(CommonConstant.NUMBER_0 != couponStatus){
			log.error("couponStatus not 0 , throw exception.");
			throw new BadRequestException();
		}
		
		// 优惠券开始时间
		Date couponStartDate = coupon.getCouponStartDate();
		if(new Date().compareTo(couponStartDate) < 0){
			log.error("couponStartDate > current time , throw exception.");
			throw new BadRequestException();
		}
		
		// 优惠券结束时间
		Date couponEndDate = coupon.getCouponEndDate();
		if(new Date().compareTo(couponEndDate) > 0){
			log.error("couponEndDate < current time , throw exception.");
			throw new BadRequestException();
		}
	}

	public void afterSubmitOrder(User user, int shopNumber, String sessionId) {
		
		log.info("----->> afterSubmitOrder generator cart key...");
		String cartKey = CartConstants.cartKey(user,shopNumber);
		log.info("cart key:"+cartKey);
		
		log.info("----->> afterSubmitOrder generator settlementKey key...");
		String settlementKey = CartConstants.settlementKey(sessionId);
		log.info("settlementKey key:"+settlementKey);
		
		log.info("----->> afterSubmitOrder generator settlementUrlKey key...");
		String settlementUrlKey = CartConstants.settlementUrlKey(sessionId);
		log.info("settlementUrlKey key:"+settlementUrlKey);
		
		JedisManager.delObject(cartKey);	// 清空购物车信息
		JedisManager.delObject(settlementKey);	// 清空结算信息
		JedisManager.delObject(settlementUrlKey);	// 清空结算地址
		
	}*/
	
	
	
	
	
}
